package com.jielihaofeng.nettyadvance.rpc.protocol;

import com.google.gson.*;

import java.io.*;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;

/**
 * @author Johnnie Wind
 * @description 序列化算法
 * @date 2021/11/18 17:44
 */
public interface Serializer {

    // 反序列化
    <T> T deserialize(Class<T> clazz, byte[] bytes);

    // 序列化
    <T> byte[] serialize(T object);

    // 序列化算法枚举： Java、Json
    enum SerializerAlgorithm implements Serializer {
        // JDK 序列化和反序列化
        Java {
            @Override
            public <T> T deserialize(Class<T> clazz, byte[] bytes) {
                try {
                    ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
                    ObjectInputStream ois = new ObjectInputStream(bis);
                    Object object = ois.readObject();
                    return (T) object;
                } catch (IOException | ClassNotFoundException e) {
                    System.err.println("反序列化失败：" + e);
                    throw new RuntimeException("反序列化失败", e);
                }
            }

            @Override
            public <T> byte[] serialize(T object) {
                try {
                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
                    new ObjectOutputStream(bos).writeObject(object);
                    return bos.toByteArray();
                } catch (IOException e) {
                    System.err.println("序列化失败：" + e);
                    throw new RuntimeException("序列化失败", e);
                }
            }
        },

        // Json 序列化和反序列化
        Json {
            @Override
            public <T> T deserialize(Class<T> clazz, byte[] bytes) {
                try {
                    Gson gson = new GsonBuilder()
                            .registerTypeAdapter(Class.class, new ClassCodec())
                            .create();
                    String json = new String(bytes, StandardCharsets.UTF_8);
                    return gson.fromJson(json, clazz);
                } catch (Exception e) {
                    System.err.println("反序列化失败：" + e);
                    throw new RuntimeException("反序列化失败", e);
                }
            }

            @Override
            public <T> byte[] serialize(T object) {
                try {
                    Gson gson = new GsonBuilder()
                            .registerTypeAdapter(Class.class, new ClassCodec())
                            .create();
                    byte[] bytes = gson.toJson(object).getBytes(StandardCharsets.UTF_8);
                    return bytes;
                } catch (Exception e) {
                    // java.lang.UnsupportedOperationException: Attempted to serialize java.lang.Class: java.lang.String. Forgot to register a type adapter?
                    System.err.println("序列化失败：" + e);
                    throw new RuntimeException("序列化失败", e);
                }
            }
        }
    }

    /**
     * @author Johnnie Wind
     * @description Gson自定义类型适配器
     * @date 2021/11/19 16:27
     */
    class ClassCodec implements JsonSerializer<Class<?>>, JsonDeserializer<Class<?>> {

        @Override
        public Class<?> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
            try {
                String str = json.getAsString();
                return Class.forName(str);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
                throw new JsonParseException(e);
            }
        }

        @Override
        public JsonElement serialize(Class<?> src, Type typeOfSrc, JsonSerializationContext context) {
            return new JsonPrimitive(src.getName());
        }
    }
}
